#ifndef LEXER_H
#define LEXER_H

#include <string>
#include <vector>
#include <map>
#include <set>
#include <memory>

struct Token {
    int line;
    std::string type;
    std::string content;
};

struct Transition {
    int fromState;
    int toState;
    char symbol;
};

class DFA {
public:
    DFA();
    void addState(int state, bool isAccepting = false);
    void addTransition(int from, int to, char symbol);
    int transition(int state, char symbol) const;
    bool isAccepting(int state) const;
    void setStartState(int state);
    int getStartState() const;

private:
    std::set<int> states;
    std::set<int> acceptingStates;
    std::map<std::pair<int, char>, int> transitions;
    int startState;
};

class NFA {
public:
    NFA();
    void addState(int state, bool isAccepting = false);
    void addTransition(int from, int to, char symbol);
    void addEpsilonTransition(int from, int to);
    std::set<int> epsilonClosure(int state) const;
    std::set<int> move(const std::set<int>& states, char symbol) const;
    DFA toDFA() const;

private:
    std::set<int> states;
    std::set<int> acceptingStates;
    std::map<std::pair<int, char>, std::set<int>> transitions;
    std::map<int, std::set<int>> epsilonTransitions;
    int startState;
};

class Lexer {
public:
    Lexer();
    ~Lexer();

    void loadGrammar(const std::string& grammarFile);
    std::vector<Token> analyze(const std::string& sourceFile);

private:
    std::map<std::string, std::string> keywords;
    std::map<std::string, std::string> operators;
    std::map<std::string, std::string> delimiters;
    std::vector<std::unique_ptr<DFA>> dfaList;
    
    bool isWhitespace(char c);
    bool isLetter(char c);
    bool isDigit(char c);
    bool isOperator(char c);
    bool isDelimiter(char c);
    std::string getTokenType(const std::string& token);
    
    bool isValidIdentifier(const std::string& token);
    bool isValidInteger(const std::string& token);
    bool isValidFloat(const std::string& token);
    bool isValidScientific(const std::string& token);
    bool isValidComplex(const std::string& token);
    
    NFA parseGrammarRule(const std::string& rule);
    void buildDFAFromGrammar();
    
    Token parseToken(const std::string& text, int lineNumber);
};

#endif 